package xueqiu

import (
	"fmt"
	"gitee.com/gcom/gbox/errors"
	"gitee.com/gcom/stockdock/comm"
	s "gitee.com/gcom/stockdock/core/support"
	"gitee.com/gcom/stockdock/crawler"
	"time"
)

type StockQuote struct {
	Code               string         `json:"code"`                                 // 股票代码
	Date               time.Time      `json:"date"`                                 // 交易日期
	Name               string         `json:"name"`                                 // 股票名称
	Close              float64        `json:"current"`                              // 收盘价
	High               float64        `json:"high"`                                 // 最高价
	Low                float64        `json:"low"`                                  // 最低价
	Open               float64        `json:"open"`                                 // 开盘价
	PreClose           float64        `json:"last_close"`                           // 昨收价
	Amplitude          float64        `json:"amplitude"`                            // 振幅（%）
	Change             float64        `json:"chg"`                                  // 涨跌额，单位：元
	Percent            float64        `json:"percent"`                              // 涨幅（％），为负表示跌幅
	Amount             float64        `json:"amount"`                               // 成交额，单位：元
	Volume             int64          `json:"volume"`                               // 成交量，单位：股
	TurnoverRate       float64        `json:"turnover_rate"`                        // 换手率，%
	VolumeRatio        float64        `json:"volume_ratio"`                         // 量比
	AvgPrice           float64        `json:"avg_price"`                            // 成交均价
	LimitUp            float64        `json:"limit_up"`                             // 涨停价，元
	LimitDown          float64        `json:"limit_down"`                           // 跌停价，元
	TotalShare         int64          `json:"total_shares"`                         // 总股本
	FloatShare         int64          `json:"float_shares"`                         // 流通股本
	MarketCapital      float64        `json:"market_capital"`                       // 总市值
	FloatMarketCapital float64        `json:"float_market_capital"`                 // 流通市值
	PEForward          float64        `json:"pe_forecast" gorm:"column:pe_forward"` // 市盈率(动)，股价除以6个月内券商预测的今年全年总净利润
	PELYR              float64        `json:"pe_lyr" gorm:"column:pe_lyr"`          // 市盈率(静)，股价除以上一年度每股盈利计算的市盈率
	PETTM              float64        `json:"pe_ttm" gorm:"column:pe_ttm"`          // 滚动市盈率，股价除以最近四个季度每股盈利计算的市盈率
	PB                 float64        `json:"pb" gorm:"column:pb"`                  // 市静率
	EPS                float64        `json:"eps" gorm:"column:eps"`                // 每股收益
	NAVPS              float64        `json:"navps" gorm:"column:navps"`            // 每股静资产，Net Asset Value Per Share
	Dividend           float64        `json:"dividend"`                             // 股息(TTM)
	DividendRate       float64        `json:"dividend_yield"`                       // 股息率(TTM)
	Profit             float64        `json:"profit"`                               // 上一年度净利润
	ProfitForward      float64        `json:"profit_forecast"`                      // 券商预测的今年全年净利润
	ProfitTTM          float64        `json:"profit_four" gorm:"column:profit_ttm"` // 四个季度滚动利润
	High52w            float64        `json:"high52w" gorm:"column:high_52w"`       // 52周最高价
	Low52w             float64        `json:"low52w" gorm:"column:low_52w"`         // 52周最低价
	ListDate           comm.Timestamp `json:"issue_date"`                           // 发行日时间戳
	Timestamp          comm.Timestamp `json:"timestamp"`                            // 报价时间戳
}

// DailyQuoteHist 雪球股票历史日报价
type DailyQuoteHist struct {
	Code          string    // 股票代号
	Date          time.Time // 报价日期
	Volume        int64     // 成交量
	Open          float64   // 开盘价
	High          float64   // 最高价
	Low           float64   // 最低价
	Close         float64   // 收盘价
	Change        float64   // 涨跌额
	Percent       float64   // 涨幅（％）
	TurnoverRate  float64   // 换手率（％）
	Amount        float64   // 成交额，单位：元
	PE            float64   `gorm:"column:pe"`  // 市盈率
	PB            float64   `gorm:"column:pb"`  // 市净率
	PS            float64   `gorm:"column:ps"`  // 市销率
	PCF           float64   `gorm:"column:pcf"` // 市现率。是股票价格与每股现金流量的比率
	MarketCapital float64   // 总市值
}

// DailyQuoteHistResp 雪球股票历史日报价返回JSON结构
// Item数组值对应字段：
//  timestamp 有值
//  volume 有值
//  open 有值
//  high 有值
//  low 有值
//  close 有值
//  chg 有值
//  percent 有值
//  turnoverrate 有值
//  amount 有值
//  volume_post
//  amount_post
//  pe 最新数据有值
//  pb 最新数据有值
//  ps 最新数据有值
//  pcf 最新数据有值
//  market_capital 最新数据有值
//  balance
//  hold_volume_cn
//  hold_ratio_cn
//  net_volume_cn
//  hold_volume_hk
//  hold_ratio_hk
//  net_volume_hk
type DailyQuoteHistResp struct {
	Code int    `json:"error_code"`        // 错误码，0表示正常
	Msg  string `json:"error_description"` // 错误消息
	Data struct {
		Symbol string      `json:"symbol"`
		Column []string    `json:"column"`
		Item   [][]float64 `json:"item"`
	} `json:"data"`
}

// 雪球股票每日报价请求类
type StockQuoteCrawlRequest struct {
	Ctx         s.TracerCtx
	Code        string
	Tm          time.Duration // timeout
	TryCount    int
	OnValueFunc crawler.CrawlOnValue
	OnErrorFunc crawler.CrawlOnError
}

func (r *StockQuoteCrawlRequest) RequestJs() string {
	return fmt.Sprintf(
		`$.ajax({url: "https://stock.xueqiu.com/v5/stock/quote.json",
		    data: {symbol: "%s", extend: "detail"},
		    xhrFields: {withCredentials: true},
		    success: function(data) {window.$$val=JSON.stringify(data);alert("%s")}
		})`, r.Code, r.Code)
}

func (r *StockQuoteCrawlRequest) Timeout() time.Duration {
	if r.Tm == 0 {
		return 10 * time.Second
	}
	return r.Tm
}

func (r *StockQuoteCrawlRequest) EvalJs(alert string) (js string, strategy crawler.CrawlEvalStrategy) {
	if alert == r.Code {
		return "window.$$val", crawler.CrawlEvalOK
	} else {
		return "", crawler.CrawlEvalSkipEvent
	}
}

func (r *StockQuoteCrawlRequest) OnValue(val string) {
	r.OnValueFunc(r, val)
}

func (r *StockQuoteCrawlRequest) OnError(err error) {
	r.OnErrorFunc(r, err)
}

func (r *StockQuoteCrawlRequest) CanRetry(err error) (d time.Duration, ok bool) {
	if r.TryCount >= 2 {
		return 0, false
	}
	if errors.HasError(err, crawler.CrawlErrTimeout) {
		r.TryCount += 1
		d := time.Duration(4*r.TryCount-3) * time.Minute
		s.WriteErrEvent(r.Ctx, fmt.Sprintf("获取股票(%s)报价失败，等待%v第%d次重试", r.Code, d, r.TryCount), err)
		return d, true
	}
	return 0, false
}

// 雪球股票每日报价历史数据请求类
type DailyQuoteHistCrawlRequest struct {
	Ctx         s.TracerCtx
	Code        string
	Tm          time.Duration // timeout
	TryCount    int
	OnValueFunc crawler.CrawlOnValue
	OnErrorFunc crawler.CrawlOnError
}

func (r *DailyQuoteHistCrawlRequest) RequestJs() string {
	return fmt.Sprintf(
		`$.ajax({url: "https://stock.xueqiu.com/v5/stock/chart/kline.json",
		    data: {symbol: "%s", begin: new Date().getTime(), period: "day", type: "before",
				count:"-900000",indicator:"kline,pe,pb,ps,pcf,market_capital,agt,ggt,balance"},
		    xhrFields: {withCredentials: true},
		    success: function(data) {window.$$val=JSON.stringify(data);alert("%s")}
		})`, r.Code, r.Code)
}

func (r *DailyQuoteHistCrawlRequest) Timeout() time.Duration {
	if r.Tm == 0 {
		return 10 * time.Second
	}
	return r.Tm
}

func (r *DailyQuoteHistCrawlRequest) EvalJs(alert string) (js string, strategy crawler.CrawlEvalStrategy) {
	if alert == r.Code {
		return "window.$$val", crawler.CrawlEvalOK
	} else {
		return "", crawler.CrawlEvalSkipEvent
	}
}

func (r *DailyQuoteHistCrawlRequest) OnValue(val string) {
	r.OnValueFunc(r, val)
}

func (r *DailyQuoteHistCrawlRequest) OnError(err error) {
	r.OnErrorFunc(r, err)
}

func (r *DailyQuoteHistCrawlRequest) CanRetry(err error) (d time.Duration, ok bool) {
	if r.TryCount >= 2 {
		return 0, false
	}
	if errors.HasError(err, crawler.CrawlErrTimeout) {
		r.TryCount += 1
		d := time.Duration(4*r.TryCount-3) * time.Minute
		s.WriteErrEvent(r.Ctx, fmt.Sprintf("获取股票(%s)历史报价失败，等待%v第%d次重试", r.Code, d, r.TryCount), err)
		return d, true
	}
	return 0, false
}
